package com.leyou.search.service.impl;

import com.leyou.clients.ItemClient;
import com.leyou.common.dto.PageDTO;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.service.IndexService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class IndexServiceImpl implements IndexService {

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private ItemClient itemClient;

    /**
     * 将spuDto对象转换成goods
     *
     * @param spuDTO 分页查询查到的spuDTO
     * @return 转换成的goods对象
     */
    @Override
    public Goods buildGoods(SpuDTO spuDTO) {
        /**
         * 1. 商品的id
         * 2. 商品标题，用于搜索
         * 3. 商品品牌id
         */
        Goods goods = new Goods();
        BeanUtils.copyProperties(spuDTO, goods);

        /**
         * 4. 商品分类id
         */
        goods.setCategoryId(spuDTO.getCid3());

        /**
         * 5. 商品预览图，从sku中取出一个即可
         */
        List<SkuDTO> skuDTOS = itemClient.querySkuBySpuId(spuDTO.getId());
        goods.setImage(StringUtils.substringBefore(skuDTOS.get(0).getImages(), ","));

        /**
         * 6. goods的销量
         */
        Long sold = 0L;
        /**
         * 7. goods的价格集合
         */
        Set<Long> prices = new HashSet<>();
        // 遍历spuID对应的sku集合
        for (SkuDTO skuDTO : skuDTOS) {
            // 销量累加
            sold += skuDTO.getSold();
            // 获取到的价格放入集合
            prices.add(skuDTO.getPrice());
        }
        goods.setSold(sold);
        // 商品spu中的所有sku的价格集合（滤重）
        goods.setPrices(prices);

        /**
         * 8. 规格参数的key和value对，用于过滤
         */
        // 创建list集合存放key-value对
        List<Map<String, Object>> specs = new ArrayList<>();
        // 获取所有可搜索的规格参数
        List<SpecParamDTO> specParamDTOS = itemClient.querySpecValuesByID(spuDTO.getId(), true).getBody();
        // 规格参数不为空，遍历集合，设置键值对
        if (!CollectionUtils.isEmpty(specParamDTOS)) {
            specParamDTOS.forEach(
                    specParamDTO -> {
                        Map<String, Object> specMap = new HashMap<>();
                        specMap.put("name", specParamDTO.getName());
                        specMap.put("value", chooseSegment(specParamDTO));
                        specs.add(specMap);
                    });
        }
        goods.setSpecs(specs);

        /**
         * 9. 自动补全的候选字段，可以包含多个值，例如分类名称、品牌名称、商品名称
         */
        ArrayList<String> suggests = new ArrayList<>();
        // 获取品牌名称
        String brandName = StringUtils.substringBefore(spuDTO.getBrandName(), "（");
        suggests.add(brandName);
        // 获取分类名称
        String categoryName = spuDTO.getCategoryName().split("/")[2];
        suggests.add(categoryName);
        // 获取商品名称
        suggests.add(spuDTO.getName());
        suggests.add(brandName + categoryName);
        suggests.add(categoryName + brandName);
        goods.setSuggestion(suggests);


        /**
         * 10. 商品更新时间
         */

        return goods;
    }

    /**
     * 根据规格参数的值选取出对应的区间
     * @param specParam 规格参数
     * @return 返回对应的区间值
     */
    private Object chooseSegment(SpecParamDTO specParam) {
        // 获取value值
        Object value = specParam.getValue();

        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        // 判断不是数字类型的字段 或者 该字段没有取值范围 或者 该字段本身是一个集合
        if (!specParam.getNumeric() || StringUtils.isBlank(specParam.getSegments()) || value instanceof Collection) {
            return value;
        }
        String result = "其他";
        // 就转换成double方便后续比较
        double val = Double.parseDouble(value.toString());

        // 获取当前规格参数的所有可选值
        for (String param : specParam.getSegments().split(",")) {
            // 切割参数
            String[] scope = param.split("-");
            // 获取到参数范围的较小值
            double begin = Double.parseDouble(scope[0]);
            // 结尾可能是一个参数，所以预先给一个最大参数值
            double end = Double.MAX_VALUE;
            // 判断给定范围是一个值还是两个值
            if (scope.length == 2) {
                // 如果是两个值，那么用第二值替换掉原先预设的最大值
                end = Double.parseDouble(scope[scope.length - 1]);
            }
            // 判断是否在当前的范围内
            if (val >= begin && val < end) {
                // 如果只有一个值，那么证明比给定的一个值还要大
                if (scope.length == 1) {
                    result = scope[0] + specParam.getUnit() + "以上";
                    // 如果有两个值，且第一个值是0，那么证明在第一个区间内，也就是比第一个区间的较大值小
                } else if (begin == 0) {
                    result = scope[1] + specParam.getUnit() + "以下";
                }else{
                    // 掐头去尾，中间就是该val的范围
                    result = param + specParam.getUnit();
                }
                break;
            }

        }
        return result;
    }

    /**
     * 获取到spu，转换成goods
     */
    @Override
    public void loadData() {
        /**
         * 1. 创建索引库
         */
        // 如果存在索引库删除
        try {
            goodsRepository.deleteIndex();
        } catch (Exception e) {
        }

        // 新建索引库
        goodsRepository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": true,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}");

        /**
         * 2. 批量导入数据
         */
        int page = 1;
        int rows = 50;
        // 1. 分页无条件查询spu
        while (true) {
            PageDTO<SpuDTO> spuDTOPageDTO = itemClient.querySpuByPage(page, rows, null, null, null, null);

            // 没有获取到数据
            if (spuDTOPageDTO.getTotalPage() == 0) {
                break;
            }

            // 取数据
            List<Goods> goods = spuDTOPageDTO.getItems()
                    .stream()
                    .map(spuDTO -> buildGoods(spuDTO))
                    .collect(Collectors.toList());
            goodsRepository.saveAll(goods);
            page++;

            // 当前是最后一页
            if (page > spuDTOPageDTO.getTotalPage()) {
                break;
            }
        }
    }

    /**
     * 监听mq的商品上架
     * @param spuId spuid
     */
    @Override
    public void saveGoodsById(Long spuId) {
        List<SpuDTO> items = itemClient.querySpuByPage(null, null, null, null, spuId, null).getItems();
        if (!CollectionUtils.isEmpty(items)) {
            goodsRepository.save(buildGoods(items.get(0)));
        }
    }

    /**
     * 监听mq的商品下架
     * @param spuId spuid
     */
    @Override
    public void deleteGoodsById(Long spuId) {
        goodsRepository.deleteById(spuId);
    }
}
